//--------------------------------------------------------------------------------
// This file is a portion of the D2D1Renderer.  It is distributed
// under the MIT License, available in the root of this distribution and 
// at the following URL:
//
// http://www.opensource.org/licenses/mit-license.php
//
// Copyright (c) Mirco Timmermann
//
//--------------------------------------------------------------------------------
#include "Stage.h"

#include "..\Objects\IKeyboardListener.h"
#include "..\Objects\IMouseListener.h"


namespace D2 {

Stage::Stage() {
	_mouseOverTarget = 0;
	_focusMouseTarget = new DisplayObject*[8];
	_activeMouseTarget = new DisplayObject*[8];

	for(int i = 0; i < 8; i++) {
		_focusMouseTarget[i] = 0;
		_activeMouseTarget[i] = 0;
	}

	_shiftKeyPressed = false;
	_strgKeyPressed = false;
	_altKeyPressed = false;

	_distanceX = 0;
	_distanceY = 0;

	_mouseX = 0;
	_mouseY = 0;

	_pre_mouseX = 0;
	_pre_mouseY = 0;

#ifdef _DEBUG
	_showOverlay = true;
	_overlay = new DisplayObjectContainer();
	_overlay->_parent = this;
	_overlay->name = "Overlay";
#endif
}

Stage::~Stage(void) {
	this->removeAllChildren();
}

bool Stage::Draw(Direct2DContext* direct2DContext, D2D1::Matrix3x2F* mtx) {
	if(!visible) return false;

	D2D1::Matrix3x2F matrix = D2D1::Matrix3x2F::Identity();

	return DisplayObjectContainer::Draw(direct2DContext, &matrix);
}

/*
* Button Mapping from one to the other.
*/
int Stage::MapKey(unsigned int key) {
	if((key & (RI_MOUSE_BUTTON_1_DOWN | RI_MOUSE_BUTTON_1_UP)) != 0) {
		return MouseEvent::BUTTON1;
	} 
	else if((key & (RI_MOUSE_BUTTON_2_DOWN | RI_MOUSE_BUTTON_2_UP)) != 0) 
	{
		return MouseEvent::BUTTON2;
	}
	else if((key & (RI_MOUSE_BUTTON_3_DOWN | RI_MOUSE_BUTTON_3_UP)) != 0) 
	{
		return MouseEvent::BUTTON3;
	}
	else if((key & (RI_MOUSE_BUTTON_4_DOWN | RI_MOUSE_BUTTON_4_UP)) != 0) 
	{
		return MouseEvent::BUTTON4;
	}
	else if((key & (RI_MOUSE_BUTTON_5_DOWN | RI_MOUSE_BUTTON_5_UP)) != 0) 
	{
		return MouseEvent::BUTTON5;
	}
	return -1;
}

LRESULT Stage::HandleWindowMessage( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) {
	switch( msg ) {	
		case WM_MOUSEMOVE:
			{
				int mouseX = (0xffff & lparam);
				int mouseY = (( 0xffff0000 & lparam ) >> 16);
				int key = MapKey(wparam);

				_OnMouseMove(key, mouseX, mouseY);
			} break;

		case WM_MOUSEWHEEL:
			{
				int mouseX = (0xffff & lparam);
				int mouseY = (( 0xffff0000 & lparam ) >> 16);
				int key = MapKey(wparam);
				int wheelDelta = ( (short)(( 0xffff0000 & wparam ) >> 16 ) );

				_OnMouseWheel(key, wheelDelta, mouseX, mouseY);
			} break;

		case WM_INPUT: 
			{
				//Determine how big the buffer should be
				UINT iBuffer;

				GetRawInputData((HRAWINPUT)lparam, RID_INPUT, NULL, &iBuffer, sizeof(RAWINPUTHEADER));
				LPBYTE lpb = new BYTE[iBuffer];
				if(lpb == NULL) {
					return 0;
				} 

				UINT readSize = GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, lpb, &iBuffer, sizeof(RAWINPUTHEADER) ) ;

				if(readSize != iBuffer)
					puts( "ERROR:  GetRawInputData didn't return correct size!" ) ;
				RAWINPUT *raw = (RAWINPUT*) lpb;                

				if (raw->header.dwType== RIM_TYPEMOUSE) {
					ProcessMouseMessage(&raw->data.mouse, hwnd);
				}
			} break;

		case WM_KEYDOWN:
			{
				BYTE buf[256];
				WORD p;
				GetKeyboardState (&buf[0]);
				ToAscii (wparam, lparam, &buf[0], &p, 0);
				char c = (char)p;

				_OnKeyDown(wparam, c);
			} break;

		case WM_KEYUP:
			{
				BYTE buf[256];
				WORD p;
				GetKeyboardState (&buf[0]);
				ToAscii (wparam, lparam, &buf[0], &p, 0);
				char c = (char)p;

				_OnKeyUp(wparam, c);
			} break;
    }

	return 0;
}

void Stage::ProcessMouseMessage(RAWMOUSE* mouse, HWND hwnd) {
	if((mouse->usButtonFlags & (RI_MOUSE_BUTTON_1_DOWN|RI_MOUSE_BUTTON_2_DOWN|RI_MOUSE_BUTTON_3_DOWN|RI_MOUSE_BUTTON_4_DOWN|RI_MOUSE_BUTTON_5_DOWN)) != 0) {
		unsigned int wparam = mouse->usButtonFlags;
		int key = MapKey(wparam);

		this->_OnMouseDown(key, _mouseX, _mouseY);
	}

	if((mouse->usButtonFlags & (RI_MOUSE_BUTTON_1_UP|RI_MOUSE_BUTTON_2_UP|RI_MOUSE_BUTTON_3_UP|RI_MOUSE_BUTTON_4_UP|RI_MOUSE_BUTTON_5_UP)) != 0) {
		unsigned int wparam = mouse->usButtonFlags;
		int key = MapKey(wparam);

		this->_OnMouseUp(key, _mouseX, _mouseY);
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////
//                                   @IKeyboardListener                                      //
///////////////////////////////////////////////////////////////////////////////////////////////
	void Stage::_OnKeyDown(unsigned int vkey, unsigned int ckey) {
		if(vkey == VK_SHIFT) { //SHIFT
			_shiftKeyPressed = true;
			return;
		}

		if(vkey == VK_CONTROL) { //CTRL/STRG
			_strgKeyPressed = true;
			return;
		}

		//key down(for stage)
		KeyboardEvent keyboardEvent2 = KeyboardEvent(KeyboardEvent::KEY_DOWN + "_STAGE", vkey, _shiftKeyPressed, _strgKeyPressed, _altKeyPressed, this);
		keyboardEvent2._charCode = ckey;
		this->dispatchEvent(keyboardEvent2);

		//
		if(_focusMouseTarget[0] != 0) {
			KeyboardEvent keyboardEvent = KeyboardEvent(KeyboardEvent::KEY_DOWN, vkey, _shiftKeyPressed, _strgKeyPressed, _altKeyPressed, _focusMouseTarget[0]);
			keyboardEvent._charCode = ckey;
			_focusMouseTarget[0]->OnKeyDown(keyboardEvent);
		}
		if(_focusMouseTarget[0] != 0) {
			KeyboardEvent keyboardEvent = KeyboardEvent(KeyboardEvent::KEY_DOWN, vkey, _shiftKeyPressed, _strgKeyPressed, _altKeyPressed, _focusMouseTarget[0]);
			keyboardEvent._charCode = ckey;
			_focusMouseTarget[0]->dispatchEvent(keyboardEvent);
		}
	}

	void Stage::_OnKeyUp(unsigned int vkey, unsigned int ckey) {
		if(vkey == VK_SHIFT) { //SHIFT
			_shiftKeyPressed = false;
			return;
		}

		if(vkey == VK_CONTROL) { //CTRL/STRG
			_strgKeyPressed = false;
			return;
		}

		if(_focusMouseTarget[0] != 0) {
			KeyboardEvent keyboardEvent = KeyboardEvent(KeyboardEvent::KEY_UP, vkey, _shiftKeyPressed, _strgKeyPressed, _altKeyPressed, _focusMouseTarget[0]);
			keyboardEvent._charCode = ckey;
			_focusMouseTarget[0]->OnKeyUp(keyboardEvent);
		}
		if(_focusMouseTarget[0] != 0) {
			KeyboardEvent keyboardEvent = KeyboardEvent(KeyboardEvent::KEY_UP, vkey, _shiftKeyPressed, _strgKeyPressed, _altKeyPressed, _focusMouseTarget[0]);
			keyboardEvent._charCode = ckey;
			_focusMouseTarget[0]->dispatchEvent(keyboardEvent);
		}

		//key up(for stage)
		KeyboardEvent keyboardEvent2 = KeyboardEvent(KeyboardEvent::KEY_UP + "_STAGE", vkey, _shiftKeyPressed, _strgKeyPressed, _altKeyPressed, this);
		keyboardEvent2._charCode = ckey;
		this->dispatchEvent(keyboardEvent2);
	}

///////////////////////////////////////////////////////////////////////////////////////////////
//                                      @IMouseListener                                      //
///////////////////////////////////////////////////////////////////////////////////////////////
	bool Stage::_OnMouseDown(int key, int x, int y) {
		//mouse down (for stage)
		MouseEvent mouseEvent = MouseEvent(MouseEvent::MOUSE_DOWN + to_string<int>(key) + "_STAGE", x, y, this);
		mouseEvent.key = key;
		mouseEvent._distanceX = this->_distanceX;
		mouseEvent._distanceY = this->_distanceY;
		this->dispatchEvent(mouseEvent);

		testMouseDownDisplayObject(key, x, y);

		//return true;
		return (_mouseOverTarget == 0); //aborts the next mouseListeners of the system.
	}

	bool Stage::_OnMouseUp(int key, int x, int y) {
		testMouseUpDisplayObject(key, x, y);

		//mouse up (for stage)
		MouseEvent mouseEvent = MouseEvent(MouseEvent::MOUSE_UP + to_string<int>(key) + "_STAGE", x, y, this);
		mouseEvent.key = key;
		mouseEvent._distanceX = this->_distanceX;
		mouseEvent._distanceY = this->_distanceY;
		this->dispatchEvent(mouseEvent);

		//return true;
		return (_mouseOverTarget == 0); //aborts the next mouseListeners of the system.
	}

	bool Stage::_OnMouseMove(int key, int x, int y) {
		//update mousePosition (for mouse distance meassure)
		this->_mouseX = x;
		this->_mouseY = y;

		//
		testMouseMoveDisplayObject(key, x, y);
		testMouseOverDisplayObject(key, x, y);

		//mouse move (for stage)
		MouseEvent mouseEvent = MouseEvent(MouseEvent::MOUSE_MOVE + "_STAGE", x, y, this);
		mouseEvent.key = key;
		mouseEvent._distanceX = this->_distanceX;
		mouseEvent._distanceY = this->_distanceY;
		this->dispatchEvent(mouseEvent);

		//return true;
		return (_mouseOverTarget == 0); //aborts the next mouseListeners of the system.
	}

	bool Stage::_OnMouseWheel(int key, int wheelDelta, int x, int y) {
		if(_mouseOverTarget != 0) {
			MouseEvent mouseEvent(MouseEvent::MOUSE_WHEEL_, x, y, _mouseOverTarget);
			mouseEvent.key = key;
			mouseEvent.wheelDelta = wheelDelta;
			mouseEvent._distanceX = this->_distanceX;
			mouseEvent._distanceY = this->_distanceY;

			_mouseOverTarget->OnMouseWheel(mouseEvent);
			_mouseOverTarget->dispatchEvent(mouseEvent);
		}

		//mouse wheel (for stage)
		MouseEvent mouseEvent = MouseEvent(MouseEvent::MOUSE_WHEEL_ + "STAGE", x, y, this);
		mouseEvent.key = key;
		mouseEvent.wheelDelta = wheelDelta;
		mouseEvent._distanceX = this->_distanceX;
		mouseEvent._distanceY = this->_distanceY;
		this->dispatchEvent(mouseEvent);

		//return true;
		return (_mouseOverTarget == 0); //aborts the next mouseListeners of the system.
	}

	bool Stage::_OnMouseDoubleClick(int key, int x, int y) {
		MouseEvent mouseEvent = MouseEvent(MouseEvent::DOUBLE_CLICK_ + to_string<int>(key) + "_STAGE", x, y, this);
		mouseEvent.key = key;
		mouseEvent._distanceX = this->_distanceX;
		mouseEvent._distanceY = this->_distanceY;
		this->dispatchEvent(mouseEvent);

		testMouseDoubleClickDisplayObject(key, x, y);

		return (_mouseOverTarget == 0);
	}

///////////////////////////////////////////////////////////////////////////////////////////////
//                                   MOUSE EVENTS                                            //
///////////////////////////////////////////////////////////////////////////////////////////////

void Stage::testMouseOverDisplayObject(int key, int x, int y) {
	DisplayObject* target = _getObjectsUnderPoint(x, y);

//MOUSE OUT
	if(_mouseOverTarget != target) {
		if(_mouseOverTarget != 0) {
			MouseEvent mouseEvent = MouseEvent(MouseEvent::MOUSE_OUT, x, y, _mouseOverTarget);
			mouseEvent.key = key;
			mouseEvent._distanceX = this->_distanceX;
			mouseEvent._distanceY = this->_distanceY;
			_mouseOverTarget->OnMouseOut(mouseEvent);
			_mouseOverTarget->dispatchEvent(mouseEvent);
		}

		if(target != 0) {
//MOUSE OVER
			MouseEvent mouseEvent = MouseEvent(MouseEvent::MOUSE_OVER, x, y, target);
			mouseEvent.key = key;
			mouseEvent._distanceX = this->_distanceX;
			mouseEvent._distanceY = this->_distanceY;
			target->OnMouseOver(mouseEvent);
			target->dispatchEvent(mouseEvent);
		}

		_mouseOverTarget = target;
	}
}

void Stage::testMouseDoubleClickDisplayObject(int key, int x, int y) {
	if(_mouseOverTarget != 0) {
		MouseEvent mouseEvent = MouseEvent(MouseEvent::DOUBLE_CLICK_ + to_string<int>(key), x, y, _mouseOverTarget);
		mouseEvent.key = key;
		mouseEvent._distanceX = this->_distanceX;
		mouseEvent._distanceY = this->_distanceY;
		//target->OnMouseDown0(mouseEvent);
		if(key == MouseEvent::BUTTON1) {
			_mouseOverTarget->OnMouseDoubleClick0(mouseEvent);
		} else if(key == MouseEvent::BUTTON2) {
			_mouseOverTarget->OnMouseDoubleClick1(mouseEvent);
		} else if(key == MouseEvent::BUTTON3) {
			_mouseOverTarget->OnMouseDoubleClick2(mouseEvent);
		} else if(key == MouseEvent::BUTTON4) {
			_mouseOverTarget->OnMouseDoubleClick3(mouseEvent);
		} else if(key == MouseEvent::BUTTON5) {
			_mouseOverTarget->OnMouseDoubleClick4(mouseEvent);
		}
		_mouseOverTarget->dispatchEvent(mouseEvent);
	}
}

void Stage::testMouseDownDisplayObject(int key, int x, int y) {
	DisplayObject* target = _getObjectsUnderPoint(x, y);

//FOCUS_LOST
	if(_focusMouseTarget[key] != target) {
		if(_focusMouseTarget[key] != 0) {
			MouseEvent mouseEvent = MouseEvent(MouseEvent::FOCUS_LOST, x, y, _focusMouseTarget[key]);
			mouseEvent.key = key;
			mouseEvent._distanceX = this->_distanceX;
			mouseEvent._distanceY = this->_distanceY;
			_focusMouseTarget[key]->OnFocusLost(mouseEvent);
			if(_focusMouseTarget[key]) {
				_focusMouseTarget[key]->dispatchEvent(mouseEvent);
			}
		}
	}
	_focusMouseTarget[key] = target;

//MOUSE_DOWN
	if(target != 0) {
		//autoForeground
		if(target->_autoForegroundEnabled) {
			target->toForeground();
		}

		MouseEvent mouseEvent = MouseEvent(MouseEvent::MOUSE_DOWN + to_string<int>(key), x, y, target);
		mouseEvent.key = key;
		mouseEvent._distanceX = this->_distanceX;
		mouseEvent._distanceY = this->_distanceY;

		if(key == MouseEvent::BUTTON1) {
			target->OnMouseDown0(mouseEvent);
		} else if(key == MouseEvent::BUTTON2) {
			target->OnMouseDown1(mouseEvent);
		} else if(key == MouseEvent::BUTTON3) {
			target->OnMouseDown2(mouseEvent);
		} else if(key == MouseEvent::BUTTON4) {
			target->OnMouseDown3(mouseEvent);
		} else if(key == MouseEvent::BUTTON5) {
			target->OnMouseDown4(mouseEvent);
		}
		target->dispatchEvent(mouseEvent);

		_activeMouseTarget[key] = target;
	}
}

void Stage::testMouseUpDisplayObject(int key, int x, int y) {
	DisplayObject* target = _getObjectsUnderPoint(x, y);

//MOUSE_UP
	if(_activeMouseTarget[key] != 0) {
		if(target == _activeMouseTarget[key]) {
			MouseEvent mouseEvent = MouseEvent(MouseEvent::MOUSE_UP + to_string<int>(key), x, y, _activeMouseTarget[key]);//"MOUSE_DOWN" + Parse::to_string<int>(e.key)
			mouseEvent.key = key;
			mouseEvent._distanceX = this->_distanceX;
			mouseEvent._distanceY = this->_distanceY;

			if(key == MouseEvent::BUTTON1) {
				_activeMouseTarget[key]->OnMouseUp0(mouseEvent);
			} else if(key == MouseEvent::BUTTON2) {
				_activeMouseTarget[key]->OnMouseUp1(mouseEvent);
			} else if(key == MouseEvent::BUTTON3) {
				_activeMouseTarget[key]->OnMouseUp2(mouseEvent);
			} else if(key == MouseEvent::BUTTON4) {
				_activeMouseTarget[key]->OnMouseUp3(mouseEvent);
			} else if(key == MouseEvent::BUTTON5) {
				_activeMouseTarget[key]->OnMouseUp4(mouseEvent);
			}
			if(_activeMouseTarget[key] != 0) {
				_activeMouseTarget[key]->dispatchEvent(mouseEvent);
			}
		} else {

//MOUSE_LEAVE
			if(_focusMouseTarget[key] != 0) {
				MouseEvent mouseEvent = MouseEvent(MouseEvent::MOUSE_LEAVE, x, y, _focusMouseTarget[key]);
				mouseEvent.key = key;
				mouseEvent._distanceX = this->_distanceX;
				mouseEvent._distanceY = this->_distanceY;
				//_focusMouseTarget[e.key]->OnMouseLeave0(mouseEvent);
				if(key == MouseEvent::BUTTON1) {
					_focusMouseTarget[key]->OnMouseLeave0(mouseEvent);
				} else if(key == MouseEvent::BUTTON2) {
					_focusMouseTarget[key]->OnMouseLeave1(mouseEvent);
				} else if(key == MouseEvent::BUTTON3) {
					_focusMouseTarget[key]->OnMouseLeave2(mouseEvent);
				} else if(key == MouseEvent::BUTTON4) {
					_focusMouseTarget[key]->OnMouseLeave3(mouseEvent);
				} else if(key == MouseEvent::BUTTON5) {
					_focusMouseTarget[key]->OnMouseLeave4(mouseEvent);
				}
				if(_focusMouseTarget[key] != 0) {
					_focusMouseTarget[key]->dispatchEvent(mouseEvent);
				}
			}
		}
	}

//MOUSE_RAISE
	if(_mouseOverTarget != 0) {
		MouseEvent mouseEvent = MouseEvent(MouseEvent::MOUSE_RAISE + to_string<int>(key), x, y, _mouseOverTarget); //const std::string &type, int stageX, int stageY, bool bubbles = false, bool cancelable = false
		mouseEvent.key = key;
		mouseEvent._distanceX = this->_distanceX;
		mouseEvent._distanceY = this->_distanceY;

		if(key == MouseEvent::BUTTON1) {
			_mouseOverTarget->OnMouseRaise0(mouseEvent);
		} else if(key == MouseEvent::BUTTON2) {
			_mouseOverTarget->OnMouseRaise1(mouseEvent);
		} else if(key == MouseEvent::BUTTON3) {
			_mouseOverTarget->OnMouseRaise2(mouseEvent);
		} else if(key == MouseEvent::BUTTON4) {
			_mouseOverTarget->OnMouseRaise3(mouseEvent);
		} else if(key == MouseEvent::BUTTON5) {
			_mouseOverTarget->OnMouseRaise4(mouseEvent);
		}
		if(_mouseOverTarget != 0) {
			_mouseOverTarget->dispatchEvent(mouseEvent);
		}
	}

	_activeMouseTarget[key] = 0;
}

void Stage::testMouseMoveDisplayObject(int key, int x, int y) {
	this->_distanceX = this->_mouseX - this->_pre_mouseX;
	this->_distanceY = this->_mouseY - this->_pre_mouseY;

//MOUSE_MOVE
	if(_mouseOverTarget != 0) {
		MouseEvent mouseEvent = MouseEvent(MouseEvent::MOUSE_MOVE, x, y, _mouseOverTarget);
		mouseEvent.key = key;
		mouseEvent._distanceX = this->_distanceX;
		mouseEvent._distanceY = this->_distanceY;
		_mouseOverTarget->OnMouseMove(mouseEvent);
		_mouseOverTarget->dispatchEvent(mouseEvent);
	}

//MOUSE_DRAG
	if(key != -1) {
		if(_activeMouseTarget[key] != 0) {
			MouseEvent mouseEvent = MouseEvent(MouseEvent::MOUSE_DRAG + to_string<int>(key), x, y, _activeMouseTarget[key]);
			mouseEvent.key = key;
			mouseEvent._distanceX = this->_distanceX;
			mouseEvent._distanceY = this->_distanceY;

			if(key == MouseEvent::BUTTON1) {
				_activeMouseTarget[key]->OnMouseDrag0(mouseEvent);
			} else if(key == MouseEvent::BUTTON2) {
				_activeMouseTarget[key]->OnMouseDrag1(mouseEvent);
			} else if(key == MouseEvent::BUTTON3) {
				_activeMouseTarget[key]->OnMouseDrag2(mouseEvent);
			} else if(key == MouseEvent::BUTTON4) {
				_activeMouseTarget[key]->OnMouseDrag3(mouseEvent);
			} else if(key == MouseEvent::BUTTON5) {
				_activeMouseTarget[key]->OnMouseDrag4(mouseEvent);
			}
			if(_activeMouseTarget[key] != 0) {
				_activeMouseTarget[key]->dispatchEvent(mouseEvent);
			}

			//mouse drag (for stage)
			MouseEvent mouseEvent2 = MouseEvent(MouseEvent::MOUSE_DRAG + to_string<int>(key) + "_STAGE", x, y, _activeMouseTarget[key]);
			mouseEvent2.key = key;
			mouseEvent2._distanceX = this->_distanceX;
			mouseEvent2._distanceY = this->_distanceY;
			this->dispatchEvent(mouseEvent2);
		}
	}

	this->_pre_mouseX = this->_mouseX;
    this->_pre_mouseY = this->_mouseY;
}

///////////////////////////////////////////////////////////////////////////////////////////////
//                                @ID2D1FrameRenderListener                                  //
///////////////////////////////////////////////////////////////////////////////////////////////

void Stage::OnD2D1FrameRender(Direct2DContext* direct2DContext) {
	Draw(direct2DContext);

#ifdef _DEBUG
	DrawOverlay(direct2DContext);
#endif
}

void Stage::focus(DisplayObject* displayObject) {
	//_focusMouseTarget[0] = displayObject;
	for(int i = 0; i < 8; i++) {
		_focusMouseTarget[i] = displayObject;
		_activeMouseTarget[i] = displayObject;
	}
}

void Stage::unfocus() {
	//_focusMouseTarget[0] = 0;
	for(int i = 0; i < 8; i++) {
		_focusMouseTarget[i] = 0;
		_activeMouseTarget[i] = 0;
	}
}

///

int Stage::GetMouseX() {
	return this->_mouseX;
}

int Stage::GetMouseY() {
	return this->_mouseY;
}

//////////////////////////////////

/*
* corrects the holding data if a displayobject is removed.
*/
void Stage::_bubbleNotifyRemoved(DisplayObject* displayObject) {
	//
	Event dataEvent(Event::REMOVED_FROM_STAGE, this);
	displayObject->OnRemovedFromStage(dataEvent);
	displayObject->dispatchEvent(dataEvent);
	//

//remove the displayObject (if it is at the moment the focus, active or over object) from the event handling, because its no longer part of the displaylist.
	if(_mouseOverTarget == displayObject) {
		_mouseOverTarget = 0;
	}

	for(int i = 0; i < 8; i++) {
		if(_focusMouseTarget[i] == displayObject) {
			_focusMouseTarget[i] = 0;
		}
		if(_activeMouseTarget[i] == displayObject) {
			_activeMouseTarget[i] = 0;
		}
	}
}

void Stage::_bubbleNotifyAdded(DisplayObject* displayObject) {
	//
	Event dataEvent(Event::ADDED_TO_STAGE, this);
	displayObject->OnAddedToStage(dataEvent);
	displayObject->dispatchEvent(dataEvent);
	//
}


//////////////////////////////////

#ifdef _DEBUG
bool Stage::DrawOverlay(Direct2DContext* direct2DContext, D2D1::Matrix3x2F* mtx) {
	if(_showOverlay) {
		D2D1::Matrix3x2F matrix = D2D1::Matrix3x2F::Identity();

		return _overlay->Draw(direct2DContext, &matrix);
	}
	return false;
}

void Stage::AddOverlayDisplayObject(DisplayObject* displayObject) {
	_overlay->addChild(displayObject);
}

void Stage::AddOverlayDisplayObjectAt(DisplayObject* displayObject,int index) {
	_overlay->addChildAt(displayObject, index);
}

void Stage::RemoveOverlayDisplayObject(DisplayObject* displayObject) {
	_overlay->removeChild(displayObject);
}

void Stage::ShowOverlay(bool show) {
	_showOverlay = show;
}

DisplayObject* Stage::_getObjectsUnderPoint(int mouseX, int mouseY) {
	bool selfContainerHit = false;
	selfContainerHit = _overlay->_hittest_boundingBox(mouseX, mouseY);

	for(int i = _overlay->getNumChildren()-1; i >= 0; i--) {
		DisplayObject* child = _overlay->getChildAt(i);

		if(!child->isVisible() || !child->mouseEnabled) continue;

		DisplayObjectContainer* displayObjectContainer = dynamic_cast<DisplayObjectContainer*>(child);
		if(displayObjectContainer != 0) { //child instanceof Container
			DisplayObject* result = 0;

			result = displayObjectContainer->_getObjectsUnderPoint(mouseX, mouseY);
			if(result != 0) return result;
		} else {
			bool hit = child->_hittest_boundingBox(mouseX, mouseY);
			if(!hit) continue;

			return child;
		}
	}

	if(selfContainerHit) {
		return this;
	}

	return DisplayObjectContainer::_getObjectsUnderPoint(mouseX, mouseY);
}
#endif

}